# -*- coding: utf-8 -*-

#    OriginDB
#    Copyright (C) 2009  Jason Power <power.jg@gmail.com>
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License along
#    with this program; if not, write to the Free Software Foundation, Inc.,
#    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

from chemdb import dbHandle
from dbobject import DBObject
from fingerprint import Fingerprint

class Compound(DBObject):
	"""This is a class that holds all the info that
		we keep about compounds in the database.
		Also it does automatic lookups for things when
		we don't have the info yet.
		PLEASE!!! Refer to things like this!!!!
		Things in this class:
		#pybel mol object
		self.mol

		#Object objects
		self.mol
		self.inchi

		#list of relation objects
		self.products
		self.reactants

		#fingerprint object
		self.fingerprint
	"""

	def __init__(self, name=-1):
		"""Name is either the name of the compound or the id(int)
		"""

		DBObject.__init__(self)

		if type(name) == str:
			self.id = dbHandle.getIdFromName(name)
		else:
			self.id = name

		#dict of items we have (overriding __dict__)
		#mol object
		self._things['mol'] = self.Mol(self.id)

		#string object
		self._things['name'] = ""
		self._things['formula'] = ""
		self._things['IUPACname'] = ""
		self._things['inchi'] = self.Inchi(self.id)

		#fingerprint object
		self._things['fingerprint'] = Fingerprint(self.id)

	def _getItem(self, name):
		"""Returns the item and also adds it to the _things dict
		   This is an interal method, please do not use.
		"""
		if self.id == -1:
			return self._things[name]
		if name=="name":
			n = dbHandle.get('name', 'compound', 'id', self.id)
			self._things['name'] = n
			return n
		elif name=="formula":
			formula = dbHandle.get('formula', 'compound', 'id', self.id)
			self._things['formula'] = formula
			return formula
		elif name=="IUPACname":
			IUPACname = dbHandle.get('IUPACname', 'compound', 'id', self.id)
			self._things['IUPACname'] = IUPACname
			return IUPACname
		elif name=="mol":
			molId = dbHandle.get('id', 'compound_mol', 'compound_id', self.id)
			if molId==-1 or None:
				molId = dbHandle.insertMol(self.id)
			self._things['mol'] = self.Mol(molId)
			return self._things['mol']
		elif name=="inchi":
			inchiId = dbHandle.get('id', 'compound_inchi', 'compound_id', self.id)
			if inchiId==-1 or None:
				inchiId = dbHandle.insertInchi(self.id)
			self._things['inchi'] = self.Inchi(inchiId)
			return self._things['inchi']
		elif name=="fingerprint":
			fingerprintId = dbHandle.get('id', 'compound_fp', 'compound_id', self.id)
			if fingerprintId == -1 or None:
				fingerprintId = dbHandle.insertFingerprint(self.id)
			self._things['fingerprint'] = Fingerprint(fingerprintId)
			return self._things['fingerprint']
		else:
			raise AttributeError, "This shouldn't ever happen..."

	def insert(self):
		if self.id != -1:
			raise AttributeError, "Object already in DB"

		self.id = dbHandle.insertCompound()

		if self._things['mol']:
			self._things['mol'].insert(self.id)
		if self._things['inchi']:
			self._things['inchi'].insert(self.id)
		if self._things['fingerprint']:
			self._things['fingerprint'].insert(self.id)

		for i in self._needToUpdate:
			self.updateDB(i)
		self._needToUpdate = []

	def updateDB(self, name):
		if self.id == -1:
			self._needToUpdate.append(name)
			return

		if name == "mol":
			#dbHandle.updateMolfile(self._things["mol"].id, "compound_id", self.id)
			raise Exception
		elif name == "inchi":
			#dbHandle.updateInchi(self._things["inchi"].id, "compound_id", self.id)
			raise Exception
		elif name == "fingerprint":
			#dbHandle.updateFingerprint(self._things["fingerprint"].id, "compound_id", self.id)
			raise Exception
		elif name == "products" or name == "reactants":
			raise NameError, "Connot set %s." % (name)
		elif name in self._things.keys():
			dbHandle.updateCompound(self.id, name, self._things[name])
		else:
			raise NameError, name

	def addProduct(self, product, reaction=None):
		raise Exception

		if reaction:
			dbHandle.insertRelation(self.id, product.id, reaction.id)
		else:
			dbHandle.insertRelation(self.id, product.id)

	def addReatant(self, reactant, reaction=None):
		raise Exception

		if reaction:
			dbHandle.insertRelation(reactant.id, self.id, reaction.id)
		else:
			dbHandle.insertRelation(reactant.id, self.id)

	class Mol(DBObject):
		"""This class holds the information for a mol object.
		It has a molfile associated with it. This is basically used
		so we can have fast searching in the database.
		"""
		def __init__(self, id=-1):

			DBObject.__init__(self)

			self.id = id

			self._things['molfile'] = ""

		def _getItem(self, name):

			if name == "molfile":
				f = dbHandle.get('molfile', 'compound_mol', 'id', self.id)
				self._things['molfile'] = f
				return f

		def insert(self, compound_id):
			if self.id != -1:
				raise AttributeError, "Object already in DB"

			self.id = dbHandle.insertMol(compound_id)

			for i in self._needToUpdate:
				self.updateDB(i)
			self._needToUpdate = []

		def updateDB(self, name):
			if self.id == -1:
				self._needToUpdate.append(name)
				return

			if name == "molfile":
				dbHandle.updateMolfile(self.id, "molfile", self._things['molfile'])

	class Inchi(DBObject):
		"""This class holds the information for a mol object.
		It has a molfile associated with it. This is basically used
		so we can have fast searching in the database.
		"""
		def __init__(self, id=-1):

			DBObject.__init__(self)

			self.id = id

			self._things['inchi'] = ""

		def _getItem(self, name):

			if name == "inchi":
				f = dbHandle.get('inchi', 'compound_inchi', 'id', self.id)
				self._things['inchi'] = f
				return f

		def insert(self, compound_id):
			if self.id != -1:
				raise AttributeError, "Object already in DB"

			self.id = dbHandle.insertInchi(compound_id)

			for i in self._needToUpdate:
				self.updateDB(i)
			self._needToUpdate = []

		def updateDB(self, name):
			if self.id == -1:
				self._needToUpdate.append(name)
				return

			if name == "inchi":
				dbHandle.updateInchi(self.id, "inchi", self._things['inchi'])

def searchForCompound(compound):
	query = {}
	if compound.name:
		query['name'] = compound.name
	if compound.formula:
		query['formula'] = compound.formula
	if compound.IUPACname:
		query['IUPACname'] = compound.IUPACname

	ids = dbHandle.searchLike(query, 'compound')

	#TODO make searching on inchi's work
	#inchiIds = []
	#if compound.inchi.inchi:
		#inchiIds = dbHandle.searchByInchi(compound.inchi)

	#for i in inchiIds:
		#if i not in ids:
			#ids.append(i)

	print ids

	return [Compound(i[0]) for i in ids]